#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "line.h"


static int  line_open(line_t *ln, char *file);
static void line_close(line_t *ln);
static int  line_read(line_t *ln, char *out[], int n);

line_t *line_create()
{
    int bufsize, memsize;
    line_t *ln = NULL;

    bufsize = 1024 * 1024;
    memsize = sizeof(line_t) + bufsize + 1;

    ln = (line_t *)malloc(memsize);
    if (ln == NULL) {
        goto done;
    }
    memset(ln, 0, memsize);
    ln->bufsize = bufsize;

    ln->open  = line_open;
    ln->close = line_close;
    ln->read  = line_read;
done:
    return ln;
}

void line_destroy(line_t *ln)
{
    free(ln);
    ln = NULL;
}

static int line_open(line_t *ln, char *file)
{
    ln->fd   = open(file, O_RDONLY);
    ln->cur  = NULL;
    ln->tail = NULL;
    ln->taillen = 0;
    return ln->fd;
}

static void line_close(line_t *ln)
{
    close(ln->fd);
    ln->fd = 0;
}

static int update_buf(line_t *ln)
{
    char *head = ln->buf;
    int len = 0;

    /* move tail data to head */
    if (ln->tail) {
        memcpy(head, ln->tail, ln->taillen);
        head += ln->taillen;
    }

    /* read data next to head */
    len = read(ln->fd, head, ln->bufsize - ln->taillen);
    if (len <= 0) {
        // printf("update: done %d\n", len);
        goto done;
    }

    len += ln->taillen;
    ln->buf[len] = 0; // this is safe, ref: line_create:memsize
    ln->cur = ln->buf; // move cursor point to buffer start.

    /* find \n from tail to head, replace with \0 */
    for (int i = len - 1; i >= 0; i--) {
        if (ln->buf[i] == '\n') {
            ln->buf[i] = '\0';
            ln->tail   = ln->buf + i + 1; // xxx\0.xx
            ln->taillen = len - 1 - i;
            break;
        }
    }

    ln->buflen = len;
done:
    // printf("update: %d\n", len);
    return len;
}

static int line_read(line_t *ln, char *out[], int n)
{
    if (ln->cur == NULL) {
        int ret = update_buf(ln);
        if (ret <= 0) {
            return ret;
        }
    }

    int idx = 0;
    char *token = NULL;
    while (idx < n && (token = strsep(&ln->cur, "\r\n"))) {
#if 0
        if (*token)
#endif
            strcpy(out[idx++], token);
    }
    return idx;
}


#if 1
int main(int argc, char *argv[])
{

    char *file = argv[1];

    line_t *ln = line_create();
    if (ln == NULL) {
        printf("line create failed\n");
        return -1;
    }

    int ret = ln->open(ln, file);
    if (ret < 0) {
        printf("can't open: %s\n", file);
        return -1;
    }

    char *lines[8] = {0};
    char buf[1024] = {0};
    lines[0] = buf;

    for (int i = 0; ; i++) {
        ret = ln->read(ln, lines, 1);
        if (ret <= 0) {
            //printf("exit: %d\n", i);
            printf("totol: %d\n", i);
            break;
        }

        printf("%s\n", lines[0]);
    }

    ln->close(ln);// line_close

    return 0;
}
#endif
